﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UriFile.cs" company="">
//   
// </copyright>
// <summary>
//   The uri file.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Core
{
    using System;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;

    /// <summary>
    ///   The uri file.
    /// </summary>
    public class UriFile : IFile
    {
        #region Fields

        /// <summary>
        ///   The _uri.
        /// </summary>
        private readonly Uri _uri;

        /// <summary>
        ///   The _description.
        /// </summary>
        private FileDescription _description;

        /// <summary>
        ///   The _path.
        /// </summary>
        private string _path;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UriFile"/> class.
        /// </summary>
        /// <param name="uri">
        /// The uri. 
        /// </param>
        public UriFile(Uri uri)
        {
            this._uri = uri;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UriFile"/> class.
        /// </summary>
        /// <param name="uriString">
        /// The uri string. 
        /// </param>
        public UriFile(string uriString)
            : this(new Uri(uriString))
        {
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        ///   The get description.
        /// </summary>
        /// <returns> The <see cref="FileDescription" /> . </returns>
        public FileDescription GetDescription()
        {
            if (this._description == null)
            {
                var request = WebRequest.Create(this._uri);
                using (var response = request.GetResponse())
                {
                    var mimeType = MimeTypes.GetByContentType(response.ContentType);
                    var name = Path.GetRandomFileName();
                    var extension = mimeType.FileExtensions.First();
                    this._description = new FileDescription(name, extension, response.ContentLength);
                }
            }

            return this._description;
        }

        /// <summary>
        ///   The get description async.
        /// </summary>
        /// <returns> The <see cref="Task" /> . </returns>
        public Task<FileDescription> GetDescriptionAsync()
        {
            // TODO Refactor to true async
            return Task.Factory.StartNew(() => this.GetDescription());
        }

        /// <summary>
        ///   The get path.
        /// </summary>
        /// <returns> The <see cref="string" /> . </returns>
        public string GetPath()
        {
            if (this._path == null)
            {
                var description = this.GetDescription();
                this._path = Path.Combine(PathUtility.GetTemporaryDirectoryPath(), description.Name);
                using (var fileStream = new FileStream(this._path, FileMode.CreateNew))
                {
                    var stream = this.GetReadStream();
                    stream.CopyTo(fileStream);
                }
            }

            return this._path;
        }

        /// <summary>
        ///   The get path async.
        /// </summary>
        /// <returns> The <see cref="Task" /> . </returns>
        public Task<string> GetPathAsync()
        {
            return Task.Factory.StartNew(() => this.GetPath());
        }

        /// <summary>
        ///   The get read stream.
        /// </summary>
        /// <returns> The <see cref="Stream" /> . </returns>
        public Stream GetReadStream()
        {
            var request = WebRequest.Create(this._uri);
            var response = request.GetResponse();
            return response.GetResponseStream();
        }

        /// <summary>
        ///   The get write stream.
        /// </summary>
        /// <returns> The <see cref="Stream" /> . </returns>
        /// <exception cref="NotImplementedException"></exception>
        public Stream GetWriteStream()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}